package com.jingbian.cppccbackend.service.impl.user;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jingbian.cppccbackend.entity.*;
import com.jingbian.cppccbackend.entity.dto.PublicOpinionPublicDTO;
import com.jingbian.cppccbackend.entity.dto.SearchPublicOpinionDTO;
import com.jingbian.cppccbackend.entity.dto.SubmitPublicOpinionDTO;
import com.jingbian.cppccbackend.entity.vo.PublicOpinionDetailVO;
import com.jingbian.cppccbackend.mapper.user.PublicOpinionAttachmentsMapper;
import com.jingbian.cppccbackend.mapper.user.PublicOpinionSignersMapper;
import com.jingbian.cppccbackend.mapper.user.PublicOpinionsMapper;
import com.jingbian.cppccbackend.mapper.user.UsersMapper;
import com.jingbian.cppccbackend.service.user.PublicOpinionsService;
import com.jingbian.cppccbackend.utils.ThreadLocalUtil;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class PublicOpinionsServiceImpl implements PublicOpinionsService {

    @Autowired
    private PublicOpinionsMapper publicOpinionsMapper;
    @Autowired
    private PublicOpinionAttachmentsMapper publicOpinionAttachmentsMapper;
    @Autowired
    private PublicOpinionSignersMapper publicOpinionSignersMapper;


    @Autowired
    private UsersMapper usersMapper;

    @Override
    @Transactional
    public void submitPublicOpinions(SubmitPublicOpinionDTO publicOpinionDTO) {
        // 获取当前用户信息
        Map<String, Object> claims = ThreadLocalUtil.get();
        Integer uid = (Integer) claims.get("uid");
        Users users = usersMapper.selectById(uid);
        List<Integer> signerUserIds = publicOpinionDTO.getSignersId();

        // 1. 处理社情民意主表
        PublicOpinions publicOpinions = new PublicOpinions();
        BeanUtils.copyProperties(publicOpinionDTO, publicOpinions);
        publicOpinions.setStatus("处理中");
        publicOpinions.setSubmitTime(LocalDateTime.now());
        publicOpinions.setUserId(uid);
        publicOpinions.setProposer(users.getUname());
        publicOpinions.setProposerRegion(users.getRegion());

        // 设置新增的字段
        publicOpinions.setTopic(publicOpinionDTO.getTopic());
        publicOpinions.setOrganizerWill(publicOpinionDTO.getOrganizerWill());

        // 如果没有联名人，直接设置为通过
        if (signerUserIds.isEmpty()) {
            publicOpinions.setIsOr(true);
            publicOpinions.setIsOrTime(LocalDateTime.now());
        }

        publicOpinionsMapper.insert(publicOpinions);

        // 2. 处理联名人
        if (signerUserIds != null && !signerUserIds.isEmpty()) {
            List<PublicOpinionSigners> signersList = new ArrayList<>();
            for (Integer userId : signerUserIds) {
                // 验证不能将自己添加为联名人
                if (userId.equals(uid)) {
                    throw new RuntimeException("不能将自己添加为联名人");
                }

                // 验证联名人是否存在且处于激活状态
                Users userSigner = usersMapper.selectById(userId);
                if (userSigner == null || !userSigner.getIsActive()) {
                    throw new RuntimeException("查无id为" + userId + "联名人");
                }
                PublicOpinionSigners signer = new PublicOpinionSigners();
                signer.setPublicOpinionId(publicOpinions.getOpinionId());
                signer.setUserId(userId);
                signer.setDisposeStatus("未处理");
                signersList.add(signer);
            }

            try {
                publicOpinionSignersMapper.batchInsert(signersList);
            } catch (Exception e) {
                throw new RuntimeException("联名人添加失败");
            }
        }

        // 3. 处理附件
        List<FileInfo> filePaths = publicOpinionDTO.getFilePath();
        if (filePaths != null && !filePaths.isEmpty()) {
            List<PublicOpinionAttachments> attachmentsList = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();

            for (FileInfo filePath : filePaths) {
                PublicOpinionAttachments attachment = new PublicOpinionAttachments();
                attachment.setPublicOpinionId(publicOpinions.getOpinionId());
                attachment.setFilePath(filePath.getUrl());
                attachment.setFileName(filePath.getName());
                attachment.setSize(filePath.getSize());
                attachment.setUploadTime(now);
                attachmentsList.add(attachment);
            }

            publicOpinionAttachmentsMapper.batchInsert(attachmentsList);
        }
    }

    @Override
    public PageInfo<PublicOpinions> getPublicOpinionsByUserId(SearchPublicOpinionDTO searchDTO) {
        // 获取当前用户信息
        Map<String, Object> claims = ThreadLocalUtil.get();
        Integer uid = (Integer) claims.get("uid");
        searchDTO.setUserId(uid);

        // 开启分页
        PageHelper.startPage(searchDTO.getPageNum(), searchDTO.getPageSize());

        // 执行查询
        List<PublicOpinions> opinions = publicOpinionsMapper.getPublicOpinionsByUserId(searchDTO);

        return new PageInfo<>(opinions);
    }

    @Override
    @Transactional
    public PublicOpinionDetailVO getDetailById(Integer opinionId) {
        // 1. 获取社情民意基本信息
        PublicOpinions opinion = publicOpinionsMapper.selectById(opinionId);
        if (opinion == null) {
            return null;
        }

        // 2. 转换为VO对象
        PublicOpinionDetailVO detailVO = new PublicOpinionDetailVO();
        BeanUtils.copyProperties(opinion, detailVO);

        // 3. 获取联名人姓名列表
        LambdaQueryWrapper<PublicOpinionSigners> signersWrapper = new LambdaQueryWrapper<>();
        signersWrapper.eq(PublicOpinionSigners::getPublicOpinionId, opinionId);
        List<PublicOpinionSigners> signersList = publicOpinionSignersMapper.selectList(signersWrapper);

        if (!signersList.isEmpty()) {
            List<Integer> signerIds = signersList.stream()
                    .map(PublicOpinionSigners::getUserId)
                    .collect(Collectors.toList());

            // 批量查询用户信息并只获取姓名
            List<Users> users = usersMapper.selectBatchIds(signerIds);
            List<String> signerNames = users.stream()
                    .map(Users::getUname)
                    .collect(Collectors.toList());

            detailVO.setSignersName(signerNames);
        }

        // 4. 获取附件信息
        LambdaQueryWrapper<PublicOpinionAttachments> attachWrapper = new LambdaQueryWrapper<>();
        attachWrapper.eq(PublicOpinionAttachments::getPublicOpinionId, opinionId);
        List<PublicOpinionAttachments> attachments = publicOpinionAttachmentsMapper.selectList(attachWrapper);

        if (!attachments.isEmpty()) {
            List<FileInfo> fileInfos = attachments.stream()
                    .map(att -> new FileInfo(att.getFileName(), att.getFilePath(), att.getSize()))
                    .collect(Collectors.toList());
            detailVO.setAttachments(fileInfos);
        }

        return detailVO;
    }


    @Override
    public ByteArrayResource generateOpinionDoc(Map<String, String> data) {
        ClassPathResource template = new ClassPathResource("word/civilWordFrame.docx");
        XWPFDocument doc = null;
        ByteArrayOutputStream out = null;

        try {
            doc = new XWPFDocument(template.getInputStream());

            // 处理所有段落中的占位符
            for (XWPFParagraph paragraph : doc.getParagraphs()) {
                replaceParagraph(paragraph, data);
            }

            // 处理表格中的占位符
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
                            replaceParagraph(paragraph, data);
                        }
                    }
                }
            }

            out = new ByteArrayOutputStream();
            doc.write(out);
            return new ByteArrayResource(out.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException("文档生成失败", e);
        } finally {
            try {
                if (doc != null) doc.close();
                if (out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 申请取消社情民意
     * @param opinionId
     * @return
     */
    @Override
    public Integer applyCancelOpinion(Integer opinionId) {
        /**
         * 返回1，则表示社情民意不存在
         * 返回2，则表示与用户id不一致
         * 返回3，申请取消社情民意成功！
         * 返回4，社情民意未过初审
         * 返回5，社情民意正在进行取消操作！
         */
        LambdaQueryWrapper<PublicOpinions> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PublicOpinions::getOpinionId,opinionId);
        /**
         * 1.对社情民意表进行查询操作
         */
        PublicOpinions publicOpinions = publicOpinionsMapper.selectOne(wrapper);
        /**
         * 1.1社情民意为空，则返回1
         */
        if(publicOpinions == null) {
            return 1;
        }
        Map<String, Object> claims = ThreadLocalUtil.get();
        Integer uid = (Integer)claims.get("uid");
        /**
         * 1.2 社情民意的提交者并非此用户，则返回2
         */
        if (!publicOpinions.getUserId().equals(uid)){
            return 2;
        }
        /**
         * 1.3如果isCancel为true，则表示正在取消阶段，返回5，不需要重复申请取消
         */
        if (publicOpinions.getIsCancel()){
            return 5;
        }
        /**
         * 1.4 这个表示社情民意未联名成功，可以通过返回4，在第二个按钮直接取消，不需要进行申请取消操作。
         */
        if (Objects.isNull(publicOpinions.getIsOr())||!publicOpinions.getIsOr()){
            return 4;
        }
        /**
         * 2.所有前置条件排除完毕，对社情民意表进行一个更新返回操作。
         */
        LambdaUpdateWrapper<PublicOpinions> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PublicOpinions::getOpinionId,opinionId).eq(PublicOpinions::getUserId,uid).set(PublicOpinions::getIsCancel,true);
        publicOpinionsMapper.update(publicOpinions, updateWrapper);
        return 3;
    }

    private void replaceParagraph(XWPFParagraph paragraph, Map<String, String> data) {
        String text = paragraph.getText();
        boolean containsPlaceholder = false;

        // 检查是否包含占位符
        for (String key : data.keySet()) {
            if (text.contains("{{" + key + "}}")) {
                containsPlaceholder = true;
                break;
            }
        }

        if (!containsPlaceholder) {
            return;
        }

        // 在修改之前保存样式信息
        XWPFRun firstRun = paragraph.getRuns().isEmpty() ? null : paragraph.getRuns().get(0);
        CTRPr styleRpr = firstRun != null ? firstRun.getCTR().getRPr() : null;

        // 替换所有占位符
        for (Map.Entry<String, String> entry : data.entrySet()) {
            text = text.replace("{{" + entry.getKey() + "}}",
                    entry.getValue() != null ? entry.getValue() : "");
        }

        // 清除所有runs
        for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
            paragraph.removeRun(i);
        }

        // 创建新的run并应用样式
        XWPFRun newRun = paragraph.createRun();
        // 设置文本
        newRun.setText(text);
    }

    @Override
    public PageInfo<PublicOpinions> getSearchPublic(PublicOpinionPublicDTO publicOpinionPublicDTO) {
        PageHelper.startPage(publicOpinionPublicDTO.getPageNum(), publicOpinionPublicDTO.getPageSize());
        List<PublicOpinions> list = publicOpinionsMapper.getSearchPublicOpinion(publicOpinionPublicDTO);
        return new PageInfo<>(list);
    }
}
